// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// DebugInfoStore




#ifndef __DebugInfoStore_H_
#define __DebugInfoStore_H_

// Debugging information is described in CorInfo.h
#include "corinfo.h"

#include "nibblestream.h"

//-----------------------------------------------------------------------------
// Information to request Debug info.
//-----------------------------------------------------------------------------
class DebugInfoRequest
{
public:
#ifdef _DEBUG
    // Must initialize via an Init*() function, not just a ctor.
    // In debug, ctor sets fields to values that will cause asserts if not initialized.
    DebugInfoRequest()
    {
        SUPPORTS_DAC;
        m_pMD = NULL;
        m_addrStart = (PCODE)NULL;
    }
#endif
    // Eventually we may have many ways to initialize a request.

    // Init given a method desc and starting address for a native code blob.
    void InitFromStartingAddr(MethodDesc * pDesc, PCODE addrCode);


    MethodDesc * GetMD() const { LIMITED_METHOD_DAC_CONTRACT; return m_pMD; }
    PCODE GetStartAddress() const { LIMITED_METHOD_DAC_CONTRACT; return m_addrStart; }

protected:
    MethodDesc * m_pMD;
    PCODE        m_addrStart;

};

//-----------------------------------------------------------------------------
// A Debug-Info Store abstracts the storage of debugging information
//-----------------------------------------------------------------------------


// We pass the IDS an allocator which it uses to hand the data back.
// pData is data the allocator may use for 'new'.
// Eg, perhaps we have multiple heaps (eg, loader-heaps per appdomain).
typedef BYTE* (*FP_IDS_NEW)(void * pData, size_t cBytes);

enum class BoundsType
{
    Instrumented, // Get the instrumented bounds (or the uninstrumented bounds if no instrumented bounds are available)
    Uninstrumented, // Get the uninstrumented bounds
};

struct DebugInfoChunks
{
    PTR_BYTE pBounds;
    ULONG32 cbBounds;
    PTR_BYTE pVars;
    ULONG32 cbVars;
    PTR_BYTE pUninstrumentedBounds;
    ULONG32 cbUninstrumentedBounds;
    PTR_BYTE pPatchpointInfo;
    ULONG32 cbPatchpointInfo;
    PTR_BYTE pRichDebugInfo;
    ULONG32 cbRichDebugInfo;
    PTR_BYTE pAsyncInfo;
    ULONG32 cbAsyncInfo;
    PTR_BYTE pEnd;
};

//-----------------------------------------------------------------------------
// Utility routines used for compression
// Note that the compression is just an implementation detail of the stores,
// and so these are just utility routines exposed to the stores.
//-----------------------------------------------------------------------------
class CompressDebugInfo
{
    // Compress incoming data and write it to the provided NibbleWriter.
    static void CompressBoundaries(
        IN ULONG32                       cMap,
        IN ICorDebugInfo::OffsetMapping *pMap,
        IN OUT NibbleWriter * pWriter
    );

    static void CompressVars(
        IN ULONG32                         cVars,
        IN ICorDebugInfo::NativeVarInfo    *vars,
        IN OUT NibbleWriter * pBuffer
    );

    static void CompressRichDebugInfo(
        IN ULONG32                           cInlineTree,
        IN ICorDebugInfo::InlineTreeNode*    pInlineTree,
        IN ULONG32                           cRichOffsetMappings,
        IN ICorDebugInfo::RichOffsetMapping* pRichOffsetMappings,
        IN OUT NibbleWriter*                 pWriter);

    static void CompressAsyncDebugInfo(
        IN ICorDebugInfo::AsyncInfo*                asyncInfo,
        IN ICorDebugInfo::AsyncSuspensionPoint*     pSuspensionPoints,
        IN ICorDebugInfo::AsyncContinuationVarInfo* pAsyncVars,
        IN ULONG                                    iAsyncVars,
        IN OUT NibbleWriter*                 pWriter);

    static DebugInfoChunks DecodeChunks(IN PTR_BYTE pDebugInfo);

public:
    // Stores the result in LoaderHeap
    static PTR_BYTE Compress(
        IN ICorDebugInfo::OffsetMapping*            pOffsetMapping,
        IN ULONG                                    iOffsetMapping,
        const InstrumentedILOffsetMapping*          pInstrumentedILBounds,
        IN ICorDebugInfo::NativeVarInfo*            pNativeVarInfo,
        IN ULONG                                    iNativeVarInfo,
        IN PatchpointInfo*                          patchpointInfo,
        IN ICorDebugInfo::InlineTreeNode*           pInlineTree,
        IN ULONG                                    iInlineTree,
        IN ICorDebugInfo::RichOffsetMapping*        pRichOffsetMappings,
        IN ULONG                                    iRichOffsetMappings,
        IN ICorDebugInfo::AsyncInfo*                asyncInfo,
        IN ICorDebugInfo::AsyncSuspensionPoint*     pSuspensionPoints,
        IN ICorDebugInfo::AsyncContinuationVarInfo* pAsyncVars,
        IN ULONG                                    iAsyncVars,
        IN LoaderHeap     * pLoaderHeap
    );

    // Uncompress data supplied by Compress functions.
    static void RestoreBoundariesAndVars(
        IN FP_IDS_NEW fpNew,
        IN void * pNewData,
        BoundsType boundsType,
        IN PTR_BYTE                         pDebugInfo,
        OUT ULONG32                       * pcMap, // number of entries in ppMap
        OUT ICorDebugInfo::OffsetMapping **ppMap, // pointer to newly allocated array
        OUT ULONG32                         *pcVars,
        OUT ICorDebugInfo::NativeVarInfo    **ppVars
    );

    // Walk the ILOffsets without needing to allocate a buffer
    static size_t WalkILOffsets(
        IN PTR_BYTE                         pDebugInfo,
        BoundsType boundsType,
        void* pContext,
        size_t (* pfnWalkILOffsets)(ICorDebugInfo::OffsetMapping *pOffsetMapping, void *pContext)
    );

#ifdef FEATURE_ON_STACK_REPLACEMENT
    static PatchpointInfo * RestorePatchpointInfo(
        IN PTR_BYTE pDebugInfo
    );
#endif

    static void RestoreRichDebugInfo(
        IN FP_IDS_NEW                          fpNew,
        IN void*                               pNewData,
        IN PTR_BYTE                            pDebugInfo,
        OUT ICorDebugInfo::InlineTreeNode**    ppInlineTree,
        OUT ULONG32*                           pNumInlineTree,
        OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings,
        OUT ULONG32*                           pNumRichMappings);

    static void RestoreAsyncDebugInfo(
        IN FP_IDS_NEW                                 fpNew,
        IN void*                                      pNewData,
        IN PTR_BYTE                                   pDebugInfo,
        OUT ICorDebugInfo::AsyncInfo*                 pAsyncInfo,
        OUT ICorDebugInfo::AsyncSuspensionPoint**     ppSuspensionPoints,
        OUT ICorDebugInfo::AsyncContinuationVarInfo** ppAsyncVars,
        OUT ULONG32*                                  pNumAsyncVars);

#ifdef DACCESS_COMPILE
    static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE pDebugInfo);
#endif
};

//-----------------------------------------------------------------------------
// Debug-Info-manager. This is like a process-wide store.
// There should be only 1 instance of this and it's process-wide.
// It will delegate to sub-stores as needed
//-----------------------------------------------------------------------------
class DebugInfoManager
{
public:
    static BOOL GetBoundariesAndVars(
        const DebugInfoRequest & request,
        IN FP_IDS_NEW fpNew,
        IN void * pNewData,
        BoundsType boundsType,
        OUT ULONG32 * pcMap,
        OUT ICorDebugInfo::OffsetMapping ** ppMap,
        OUT ULONG32 * pcVars,
        OUT ICorDebugInfo::NativeVarInfo ** ppVars);

    static BOOL GetRichDebugInfo(
        const DebugInfoRequest & request,
        IN FP_IDS_NEW fpNew, IN void * pNewData,
        OUT ICorDebugInfo::InlineTreeNode**    ppInlineTree,
        OUT ULONG32*                           pNumInlineTree,
        OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings,
        OUT ULONG32*                           pNumRichMappings);

    static BOOL GetAsyncDebugInfo(
        const DebugInfoRequest & request,
        IN FP_IDS_NEW fpNew, IN void * pNewData,
        OUT ICorDebugInfo::AsyncInfo* pAsyncInfo,
        OUT ICorDebugInfo::AsyncSuspensionPoint** ppSuspensionPoints,
        OUT ICorDebugInfo::AsyncContinuationVarInfo** ppAsyncVars,
        OUT ULONG32* pcAsyncVars);

#ifdef DACCESS_COMPILE
    static void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo);
#endif
};

#define DebugInfoFat 0

#endif // __DebugInfoStore_H_
